#!/usr/bin/env python3
"""
自动化MCP监控脚本
功能：
- 定期检测MCP服务状态
- 自动重启失败的服务
- 发送告警通知
- 生成监控仪表板
"""

import time
import json
import subprocess
import threading
import schedule
from datetime import datetime, timedelta
from pathlib import Path
import logging
from mcp_health_monitor import MCPHealthMonitor
try:
    import smtplib
    from email.mime.text import MimeText
    from email.mime.multipart import MimeMultipart
    EMAIL_AVAILABLE = True
except ImportError:
    EMAIL_AVAILABLE = False

class MCPAutoMonitor:
    def __init__(self, config_file="monitor_config.json"):
        self.config_file = config_file
        self.base_dir = Path(__file__).parent
        self.load_config()
        self.setup_logging()
        self.health_monitor = MCPHealthMonitor()
        self.monitoring_active = False
        self.last_status = None
        self.alert_history = []
        
    def load_config(self):
        """加载监控配置"""
        config_path = self.base_dir / self.config_file
        
        # 默认配置
        default_config = {
            "monitoring": {
                "check_interval_minutes": 5,
                "auto_restart": True,
                "max_restart_attempts": 3,
                "restart_cooldown_minutes": 10
            },
            "alerts": {
                "enabled": True,
                "email": {
                    "enabled": False,
                    "smtp_server": "smtp.gmail.com",
                    "smtp_port": 587,
                    "username": "",
                    "password": "",
                    "to_addresses": []
                },
                "webhook": {
                    "enabled": False,
                    "url": "",
                    "headers": {}
                }
            },
            "dashboard": {
                "enabled": True,
                "port": 8080,
                "refresh_interval_seconds": 30
            },
            "logging": {
                "level": "INFO",
                "max_log_files": 10,
                "max_log_size_mb": 50
            }
        }
        
        if config_path.exists():
            try:
                with open(config_path, 'r', encoding='utf-8') as f:
                    user_config = json.load(f)
                # 合并配置
                self.config = {**default_config, **user_config}
            except Exception as e:
                print(f"配置文件加载失败，使用默认配置: {e}")
                self.config = default_config
        else:
            self.config = default_config
            # 创建默认配置文件
            with open(config_path, 'w', encoding='utf-8') as f:
                json.dump(default_config, f, indent=2, ensure_ascii=False)
    
    def setup_logging(self):
        """设置日志"""
        log_level = getattr(logging, self.config["logging"]["level"])
        
        logging.basicConfig(
            level=log_level,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler('auto_monitor.log'),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger(__name__)
    
    def check_mcp_status(self):
        """检查MCP状态"""
        try:
            report = self.health_monitor.run_all_checks()
            current_status = report["overall_status"]
            
            # 状态变化检测
            if self.last_status != current_status:
                self.logger.info(f"MCP状态变化: {self.last_status} -> {current_status}")
                
                # 发送告警
                if current_status in ["warning", "critical"]:
                    self.send_alert("MCP状态告警", f"MCP服务状态变为: {current_status}", report)
                elif current_status == "healthy" and self.last_status in ["warning", "critical"]:
                    self.send_alert("MCP状态恢复", "MCP服务状态已恢复正常", report)
                
                self.last_status = current_status
            
            # 自动重启逻辑
            if (current_status == "critical" and 
                self.config["monitoring"]["auto_restart"] and 
                self.should_attempt_restart()):
                self.attempt_restart()
            
            # 保存状态历史
            self.save_status_history(report)
            
            return report
            
        except Exception as e:
            self.logger.error(f"状态检查失败: {e}")
            return None
    
    def should_attempt_restart(self):
        """判断是否应该尝试重启"""
        now = datetime.now()
        cooldown_minutes = self.config["monitoring"]["restart_cooldown_minutes"]
        
        # 检查冷却时间
        recent_restarts = [alert for alert in self.alert_history 
                          if alert.get("type") == "restart" and 
                          datetime.fromisoformat(alert["timestamp"]) > now - timedelta(minutes=cooldown_minutes)]
        
        max_attempts = self.config["monitoring"]["max_restart_attempts"]
        return len(recent_restarts) < max_attempts
    
    def attempt_restart(self):
        """尝试重启MCP服务"""
        try:
            self.logger.info("尝试重启MCP服务...")
            
            # 停止现有进程
            subprocess.run(["taskkill", "/f", "/im", "python.exe"], 
                          capture_output=True, text=True)
            
            time.sleep(5)  # 等待进程完全停止
            
            # 启动新进程
            main_file = self.base_dir / "main.py"
            if main_file.exists():
                subprocess.Popen(["python", str(main_file)], 
                               cwd=str(self.base_dir))
                
                self.logger.info("MCP服务重启命令已执行")
                
                # 记录重启事件
                restart_event = {
                    "type": "restart",
                    "timestamp": datetime.now().isoformat(),
                    "reason": "自动重启 - 服务状态为critical"
                }
                self.alert_history.append(restart_event)
                
                # 发送重启通知
                self.send_alert("MCP服务重启", "已尝试自动重启MCP服务", restart_event)
            else:
                self.logger.error("找不到main.py文件，无法重启服务")
                
        except Exception as e:
            self.logger.error(f"重启失败: {e}")
    
    def send_alert(self, subject, message, data=None):
        """发送告警"""
        if not self.config["alerts"]["enabled"]:
            return
        
        alert_data = {
            "timestamp": datetime.now().isoformat(),
            "subject": subject,
            "message": message,
            "data": data
        }
        
        # 邮件告警
        if self.config["alerts"]["email"]["enabled"]:
            self.send_email_alert(alert_data)
        
        # Webhook告警
        if self.config["alerts"]["webhook"]["enabled"]:
            self.send_webhook_alert(alert_data)
        
        # 记录告警历史
        self.alert_history.append(alert_data)
        
        # 限制历史记录数量
        if len(self.alert_history) > 100:
            self.alert_history = self.alert_history[-50:]
    
    def send_email_alert(self, alert_data):
        """发送邮件告警"""
        if not EMAIL_AVAILABLE:
            self.logger.warning("邮件模块不可用，跳过邮件告警")
            return
            
        try:
            email_config = self.config["alerts"]["email"]
            
            msg = MimeMultipart()
            msg['From'] = email_config["username"]
            msg['Subject'] = f"[MCP监控] {alert_data['subject']}"
            
            body = f"""
            MCP监控告警
            
            时间: {alert_data['timestamp']}
            主题: {alert_data['subject']}
            消息: {alert_data['message']}
            
            详细信息:
            {json.dumps(alert_data['data'], indent=2, ensure_ascii=False) if alert_data['data'] else '无'}
            """
            
            msg.attach(MimeText(body, 'plain', 'utf-8'))
            
            server = smtplib.SMTP(email_config["smtp_server"], email_config["smtp_port"])
            server.starttls()
            server.login(email_config["username"], email_config["password"])
            
            for to_addr in email_config["to_addresses"]:
                msg['To'] = to_addr
                server.send_message(msg)
                del msg['To']
            
            server.quit()
            self.logger.info("邮件告警发送成功")
            
        except Exception as e:
            self.logger.error(f"邮件告警发送失败: {e}")
    
    def send_webhook_alert(self, alert_data):
        """发送Webhook告警"""
        try:
            import requests
            
            webhook_config = self.config["alerts"]["webhook"]
            
            payload = {
                "text": f"MCP监控告警: {alert_data['subject']}",
                "timestamp": alert_data['timestamp'],
                "message": alert_data['message'],
                "data": alert_data['data']
            }
            
            response = requests.post(
                webhook_config["url"],
                json=payload,
                headers=webhook_config["headers"],
                timeout=10
            )
            
            if response.status_code == 200:
                self.logger.info("Webhook告警发送成功")
            else:
                self.logger.error(f"Webhook告警发送失败: {response.status_code}")
                
        except Exception as e:
            self.logger.error(f"Webhook告警发送失败: {e}")
    
    def save_status_history(self, report):
        """保存状态历史"""
        try:
            history_file = self.base_dir / "status_history.json"
            
            # 读取现有历史
            if history_file.exists():
                with open(history_file, 'r', encoding='utf-8') as f:
                    history = json.load(f)
            else:
                history = []
            
            # 添加新记录
            history.append({
                "timestamp": report["timestamp"],
                "status": report["overall_status"],
                "success_rate": report["success_rate"],
                "checks": {name: result["status"] for name, result in report["checks"].items()}
            })
            
            # 限制历史记录数量（保留最近1000条）
            if len(history) > 1000:
                history = history[-500:]
            
            # 保存历史
            with open(history_file, 'w', encoding='utf-8') as f:
                json.dump(history, f, indent=2, ensure_ascii=False)
                
        except Exception as e:
            self.logger.error(f"保存状态历史失败: {e}")
    
    def generate_dashboard_data(self):
        """生成仪表板数据"""
        try:
            # 读取状态历史
            history_file = self.base_dir / "status_history.json"
            if history_file.exists():
                with open(history_file, 'r', encoding='utf-8') as f:
                    history = json.load(f)
            else:
                history = []
            
            # 计算统计信息
            now = datetime.now()
            last_24h = [h for h in history if 
                       datetime.fromisoformat(h["timestamp"]) > now - timedelta(hours=24)]
            last_1h = [h for h in history if 
                      datetime.fromisoformat(h["timestamp"]) > now - timedelta(hours=1)]
            
            # 获取1小时内的计算器运算操作
            calculator_ops_1h = []
            try:
                calculator_log_file = self.base_dir / "calculator.log"
                if calculator_log_file.exists():
                    with open(calculator_log_file, 'r', encoding='utf-8', errors='replace') as f:
                        lines = f.readlines()
                    
                    for line in reversed(lines[-1000:]):  # 检查最近1000行
                        line = line.strip()
                        if not line:
                            continue
                        
                        try:
                            parts = line.split(' - ', 3)
                            if len(parts) >= 4:
                                timestamp_str = parts[0]
                                module = parts[1]
                                level = parts[2]
                                message = parts[3]
                                
                                if module == 'CalculatorMCP' and level == 'INFO':
                                    try:
                                        timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S,%f')
                                        if timestamp > now - timedelta(hours=1):
                                            if any(keyword in message for keyword in ['运算:', '表达式计算:', '统计分析', '单位转换:']):
                                                calculator_ops_1h.append({
                                                    'timestamp': timestamp.isoformat(),
                                                    'status': 'error' if any(err in message for err in ['失败', '错误', 'WARNING']) else 'success'
                                                })
                                    except:
                                        continue
                        except:
                            continue
            except Exception as e:
                self.logger.error(f"读取计算器日志失败: {e}")
            
            # 计算一小时内的操作统计（包含监控操作和计算器运算）
            total_calc_ops = len(calculator_ops_1h)
            successful_calc_ops = len([op for op in calculator_ops_1h if op['status'] == 'success'])
            failed_calc_ops = len([op for op in calculator_ops_1h if op['status'] == 'error'])
            
            hourly_stats = {
                "total_operations": len(last_1h) + total_calc_ops,
                "successful_operations": len([h for h in last_1h if h["status"] == "healthy"]) + successful_calc_ops,
                "failed_operations": len([h for h in last_1h if h["status"] in ["warning", "critical"]]) + failed_calc_ops,
                "success_rate_1h": (len([h for h in last_1h if h["status"] == "healthy"]) + successful_calc_ops) / max(len(last_1h) + total_calc_ops, 1) * 100,
                "avg_interval": self.config["monitoring"]["check_interval_minutes"] if last_1h else 0,
                "last_operation_time": last_1h[-1]["timestamp"] if last_1h else None,
                "calculator_operations": total_calc_ops,
                "calculator_successful": successful_calc_ops,
                "calculator_failed": failed_calc_ops
            }
            
            dashboard_data = {
                "current_status": self.last_status or "unknown",
                "last_check": history[-1]["timestamp"] if history else None,
                "uptime_24h": len([h for h in last_24h if h["status"] == "healthy"]) / max(len(last_24h), 1) * 100,
                "total_checks": len(history),
                "recent_alerts": self.alert_history[-10:],
                "status_distribution": {
                    "healthy": len([h for h in last_24h if h["status"] == "healthy"]),
                    "warning": len([h for h in last_24h if h["status"] == "warning"]),
                    "critical": len([h for h in last_24h if h["status"] == "critical"])
                },
                "hourly_operations": hourly_stats,
                "history": last_24h[-50:]  # 最近50条记录
            }
            
            return dashboard_data
            
        except Exception as e:
            self.logger.error(f"生成仪表板数据失败: {e}")
            return {}
    
    def get_detailed_operations(self, limit=50):
        """获取详细的操作记录"""
        try:
            # 读取状态历史
            history_file = self.base_dir / "status_history.json"
            if history_file.exists():
                with open(history_file, 'r', encoding='utf-8') as f:
                    history = json.load(f)
            else:
                history = []
            
            # 按时间倒序排列，获取最近的记录
            sorted_history = sorted(history, key=lambda x: x['timestamp'], reverse=True)
            
            # 限制返回数量
            limited_history = sorted_history[:limit]
            
            # 为每条记录添加格式化的时间和状态描述
            detailed_operations = []
            for record in limited_history:
                try:
                    timestamp = datetime.fromisoformat(record['timestamp'])
                    formatted_time = timestamp.strftime('%Y-%m-%d %H:%M:%S')
                    
                    operation = {
                        'id': len(detailed_operations) + 1,
                        'timestamp': record['timestamp'],
                        'formatted_time': formatted_time,
                        'status': record['status'],
                        'status_text': '健康' if record['status'] == 'healthy' else '异常',
                        'status_class': 'success' if record['status'] == 'healthy' else 'danger',
                        'checks': record.get('checks', {}),
                        'success_rate': record.get('success_rate', 0)
                    }
                    
                    # 添加检查项目详情
                    if 'checks' in record and isinstance(record['checks'], dict):
                        check_details = []
                        for check_name, check_status in record['checks'].items():
                            check_details.append({
                                'name': check_name,
                                'status': check_status,
                                'status_text': '正常' if check_status == 'healthy' else '异常'
                            })
                        operation['check_details'] = check_details
                    else:
                        operation['check_details'] = []
                    
                    detailed_operations.append(operation)
                    
                except Exception as e:
                    self.logger.error(f"处理操作记录失败: {e}")
                    continue
            
            return {
                'operations': detailed_operations,
                'total_count': len(history),
                'displayed_count': len(detailed_operations),
                'last_updated': datetime.now().isoformat()
            }
            
        except Exception as e:
            self.logger.error(f"获取详细操作记录失败: {e}")
            return {
                'operations': [],
                'total_count': 0,
                'displayed_count': 0,
                'last_updated': datetime.now().isoformat(),
                'error': str(e)
            }
    
    def get_calculator_operations(self, limit=100):
        """获取计算器运算操作记录"""
        try:
            # 读取计算器日志文件
            calculator_log_file = self.base_dir / "calculator.log"
            operations = []
            
            if calculator_log_file.exists():
                with open(calculator_log_file, 'r', encoding='utf-8', errors='replace') as f:
                    lines = f.readlines()
                
                # 解析日志文件，提取运算操作
                for line in reversed(lines[-limit*3:]):  # 读取更多行以确保获得足够的操作记录
                    line = line.strip()
                    if not line:
                        continue
                    
                    try:
                        # 解析日志行格式: 时间戳 - 模块 - 级别 - 消息
                        parts = line.split(' - ', 3)
                        if len(parts) >= 4:
                            timestamp_str = parts[0]
                            module = parts[1]
                            level = parts[2]
                            message = parts[3]
                            
                            # 只处理计算器相关的INFO级别日志
                            if module == 'CalculatorMCP' and level == 'INFO':
                                # 解析不同类型的操作
                                operation_info = self._parse_calculator_operation(message, timestamp_str)
                                if operation_info:
                                    operations.append(operation_info)
                                    
                                    if len(operations) >= limit:
                                        break
                    except Exception as e:
                        continue
            
            # 按时间排序（最新的在前）
            operations.sort(key=lambda x: x['timestamp'], reverse=True)
            
            return {
                'operations': operations[:limit],
                'total_count': len(operations),
                'displayed_count': min(len(operations), limit),
                'last_updated': datetime.now().isoformat()
            }
            
        except Exception as e:
            self.logger.error(f"获取计算器操作记录失败: {e}")
            return {
                'operations': [],
                'total_count': 0,
                'displayed_count': 0,
                'last_updated': datetime.now().isoformat(),
                'error': str(e)
            }
    
    def _parse_calculator_operation(self, message, timestamp_str):
        """解析计算器操作日志消息"""
        try:
            # 解析时间戳
            timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S,%f')
            formatted_time = timestamp.strftime('%Y-%m-%d %H:%M:%S')
            
            operation = {
                'id': 0,  # 将在返回时设置
                'timestamp': timestamp.isoformat(),
                'formatted_time': formatted_time,
                'type': 'unknown',
                'operation': '',
                'result': '',
                'execution_time': 0.0,
                'status': 'success',
                'status_text': '成功',
                'status_class': 'success'
            }
            
            # 解析不同类型的操作消息
            if '运算:' in message:
                # 基础运算: 加法运算: 10 + 5 = 15.0
                if '加法运算:' in message:
                    operation['type'] = 'add'
                    operation['operation'] = '加法运算'
                elif '减法运算:' in message:
                    operation['type'] = 'subtract'
                    operation['operation'] = '减法运算'
                elif '乘法运算:' in message:
                    operation['type'] = 'multiply'
                    operation['operation'] = '乘法运算'
                elif '除法运算:' in message:
                    operation['type'] = 'divide'
                    operation['operation'] = '除法运算'
                elif '幂运算:' in message:
                    operation['type'] = 'power'
                    operation['operation'] = '幂运算'
                elif '平方根运算:' in message:
                    operation['type'] = 'square_root'
                    operation['operation'] = '平方根运算'
                elif '阶乘运算:' in message:
                    operation['type'] = 'factorial'
                    operation['operation'] = '阶乘运算'
                elif '自然对数运算:' in message:
                    operation['type'] = 'logarithm'
                    operation['operation'] = '对数运算'
                elif '三角函数运算:' in message:
                    operation['type'] = 'trigonometry'
                    operation['operation'] = '三角函数运算'
                
                # 提取运算表达式和结果
                if ':' in message:
                    result_part = message.split(':', 1)[1].strip()
                    operation['result'] = result_part
                    
            elif '表达式计算:' in message:
                operation['type'] = 'calculate'
                operation['operation'] = '表达式计算'
                if ':' in message:
                    result_part = message.split(':', 1)[1].strip()
                    operation['result'] = result_part
                    
            elif '统计分析完成' in message:
                operation['type'] = 'statistics'
                operation['operation'] = '统计分析'
                operation['result'] = message
                
            elif '单位转换:' in message:
                operation['type'] = 'unit_conversion'
                operation['operation'] = '单位转换'
                if ':' in message:
                    result_part = message.split(':', 1)[1].strip()
                    operation['result'] = result_part
                    
            elif '执行时间:' in message:
                # 解析执行时间: 函数 add 执行时间: 0.0003秒
                if '执行时间:' in message and '秒' in message:
                    time_part = message.split('执行时间:')[1].strip()
                    time_str = time_part.replace('秒', '').strip()
                    try:
                        operation['execution_time'] = float(time_str)
                    except:
                        pass
                return None  # 执行时间记录不作为独立操作返回
                
            elif '性能统计信息' in message or '重置' in message:
                operation['type'] = 'system'
                operation['operation'] = '系统操作'
                operation['result'] = message
                
            else:
                return None  # 不是我们关心的操作类型
            
            # 检查是否是错误消息
            if '失败' in message or '错误' in message or 'WARNING' in message:
                operation['status'] = 'error'
                operation['status_text'] = '失败'
                operation['status_class'] = 'danger'
            
            return operation
            
        except Exception as e:
            return None
    
    def start_monitoring(self):
        """开始监控"""
        if self.monitoring_active:
            self.logger.warning("监控已在运行中")
            return
        
        self.monitoring_active = True
        self.logger.info("开始MCP自动监控...")
        
        # 设置定时任务
        interval = self.config["monitoring"]["check_interval_minutes"]
        schedule.every(interval).minutes.do(self.check_mcp_status)
        
        # 立即执行一次检查
        self.check_mcp_status()
        
        # 启动仪表板（如果启用）
        if self.config["dashboard"]["enabled"]:
            dashboard_thread = threading.Thread(target=self.start_dashboard, daemon=True)
            dashboard_thread.start()
        
        # 监控循环
        try:
            while self.monitoring_active:
                schedule.run_pending()
                time.sleep(1)
        except KeyboardInterrupt:
            self.logger.info("收到停止信号，正在停止监控...")
        finally:
            self.stop_monitoring()
    
    def stop_monitoring(self):
        """停止监控"""
        self.monitoring_active = False
        schedule.clear()
        self.logger.info("MCP监控已停止")
    
    def start_dashboard(self):
        """启动监控仪表板"""
        try:
            from http.server import HTTPServer, BaseHTTPRequestHandler
            import urllib.parse
            
            class DashboardHandler(BaseHTTPRequestHandler):
                def __init__(self, monitor, *args, **kwargs):
                    self.monitor = monitor
                    super().__init__(*args, **kwargs)
                
                def do_GET(self):
                    if self.path == '/' or self.path == '/dashboard':
                        self.send_response(200)
                        self.send_header('Content-type', 'text/html; charset=utf-8')
                        self.end_headers()
                        
                        dashboard_data = self.monitor.generate_dashboard_data()
                        html = self.generate_dashboard_html(dashboard_data)
                        self.wfile.write(html.encode('utf-8'))
                    
                    elif self.path == '/api/status':
                        self.send_response(200)
                        self.send_header('Content-type', 'application/json')
                        self.end_headers()
                        
                        dashboard_data = self.monitor.generate_dashboard_data()
                        self.wfile.write(json.dumps(dashboard_data, ensure_ascii=False).encode('utf-8'))
                    
                    elif self.path == '/operations' or self.path == '/operations.html':
                        self.send_response(200)
                        self.send_header('Content-type', 'text/html; charset=utf-8')
                        self.end_headers()
                        
                        operations_data = self.monitor.get_detailed_operations()
                        html = self.generate_operations_html(operations_data)
                        self.wfile.write(html.encode('utf-8'))
                    
                    elif self.path == '/api/operations':
                        self.send_response(200)
                        self.send_header('Content-type', 'application/json')
                        self.end_headers()
                        
                        operations_data = self.monitor.get_detailed_operations()
                        self.wfile.write(json.dumps(operations_data, ensure_ascii=False).encode('utf-8'))
                    
                    elif self.path == '/calculator-operations' or self.path == '/calculator-operations.html':
                        self.send_response(200)
                        self.send_header('Content-type', 'text/html; charset=utf-8')
                        self.end_headers()
                        
                        calculator_data = self.monitor.get_calculator_operations()
                        html = self.generate_calculator_operations_html(calculator_data)
                        self.wfile.write(html.encode('utf-8'))
                    
                    elif self.path == '/api/calculator-operations':
                        self.send_response(200)
                        self.send_header('Content-type', 'application/json')
                        self.end_headers()
                        
                        calculator_data = self.monitor.get_calculator_operations()
                        self.wfile.write(json.dumps(calculator_data, ensure_ascii=False).encode('utf-8'))
                    
                    else:
                        self.send_response(404)
                        self.end_headers()
                
                def generate_dashboard_html(self, data):
                    status_color = {
                        'healthy': '#28a745',
                        'warning': '#ffc107', 
                        'critical': '#dc3545',
                        'unknown': '#6c757d'
                    }
                    
                    # 获取配置信息
                    refresh_interval = self.monitor.config['dashboard']['refresh_interval_seconds']
                    current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                    
                    return f"""
                    <!DOCTYPE html>
                    <html>
                    <head>
                        <title>MCP监控仪表板</title>
                        <meta charset="utf-8">
                        <meta name="viewport" content="width=device-width, initial-scale=1">
                        <style>
                            body {{ font-family: Arial, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }}
                            .container {{ max-width: 1200px; margin: 0 auto; }}
                            .header {{ background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
                            .status-card {{ background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
                            .status-indicator {{ display: inline-block; width: 20px; height: 20px; border-radius: 50%; margin-right: 10px; }}
                            .grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; }}
                            .metric {{ text-align: center; padding: 15px; background: #f8f9fa; border-radius: 4px; margin: 10px 0; }}
                            .metric-value {{ font-size: 2em; font-weight: bold; color: #007bff; }}
                            .metric-label {{ color: #6c757d; }}
                            .alert-item {{ padding: 10px; border-left: 4px solid #dc3545; background: #f8f9fa; margin: 5px 0; }}
                            .refresh-info {{ color: #6c757d; font-size: 0.9em; }}
                        </style>
                        <script>
                            function refreshData() {{
                                fetch('/api/status')
                                    .then(response => response.json())
                                    .then(data => {{
                                        location.reload();
                                    }})
                                    .catch(error => console.error('Error:', error));
                            }}
                            
                            setInterval(refreshData, {refresh_interval * 1000});
                        </script>
                    </head>
                    <body>
                        <div class="container">
                            <div class="header">
                                <h1>🏥 MCP监控仪表板</h1>
                                <p class="refresh-info">自动刷新间隔: {refresh_interval}秒 | 最后更新: {current_time}</p>
                                <div class="mt-3">
                                    <a href="/operations" class="btn btn-primary me-2">📋 查看监控操作</a>
                                    <a href="/calculator-operations" class="btn btn-success">🧮 查看运算操作</a>
                                </div>
                            </div>
                            
                            <div class="status-card">
                                <h2>
                                    <span class="status-indicator" style="background-color: {status_color.get(data.get('current_status', 'unknown'), '#6c757d')}"></span>
                                    当前状态: {data.get('current_status', 'unknown').upper()}
                                </h2>
                                <p>最后检查: {data.get('last_check', '未知')}</p>
                            </div>
                            
                            <div class="grid">
                                <div class="status-card">
                                    <h3>📊 24小时统计</h3>
                                    <div class="metric">
                                        <div class="metric-value">{data.get('uptime_24h', 0):.1f}%</div>
                                        <div class="metric-label">可用率</div>
                                    </div>
                                    <div class="metric">
                                        <div class="metric-value">{data.get('total_checks', 0)}</div>
                                        <div class="metric-label">总检查次数</div>
                                    </div>
                                </div>
                                
                                <div class="status-card">
                                    <h3>⏰ 1小时内操作统计</h3>
                                    <div class="metric">
                                        <div class="metric-value">{data.get('hourly_operations', {}).get('total_operations', 0)}</div>
                                        <div class="metric-label">总操作次数</div>
                                    </div>
                                    <div class="metric">
                                        <div class="metric-value" style="color: #28a745">{data.get('hourly_operations', {}).get('successful_operations', 0)}</div>
                                        <div class="metric-label">成功操作</div>
                                    </div>
                                    <div class="metric">
                                        <div class="metric-value">{data.get('hourly_operations', {}).get('success_rate_1h', 0):.1f}%</div>
                                        <div class="metric-label">成功率</div>
                                    </div>
                                    <div class="metric">
                                        <div class="metric-value" style="color: #17a2b8">{data.get('hourly_operations', {}).get('calculator_operations', 0)}</div>
                                        <div class="metric-label">计算器运算</div>
                                    </div>
                                </div>
                                
                                <div class="status-card">
                                    <h3>📈 状态分布</h3>
                                    <div class="metric">
                                        <div class="metric-value" style="color: #28a745">{data.get('status_distribution', {}).get('healthy', 0)}</div>
                                        <div class="metric-label">健康</div>
                                    </div>
                                    <div class="metric">
                                        <div class="metric-value" style="color: #ffc107">{data.get('status_distribution', {}).get('warning', 0)}</div>
                                        <div class="metric-label">警告</div>
                                    </div>
                                    <div class="metric">
                                        <div class="metric-value" style="color: #dc3545">{data.get('status_distribution', {}).get('critical', 0)}</div>
                                        <div class="metric-label">严重</div>
                                    </div>
                                </div>
                            </div>
                            
                            <div class="status-card">
                                <h3>🚨 最近告警</h3>
                                {''.join([f'<div class="alert-item"><strong>{alert.get("subject", "")}</strong><br>{alert.get("message", "")}<br><small>{alert.get("timestamp", "")}</small></div>' for alert in data.get('recent_alerts', [])])}
                                {"<p>暂无告警</p>" if not data.get('recent_alerts') else ""}
                            </div>
                        </div>
                    </body>
                    </html>
                    """
                
                def log_message(self, format, *args):
                    pass  # 禁用访问日志
                
                def generate_operations_html(self, operations_data):
                    """生成操作详情页面HTML"""
                    operations = operations_data.get('operations', [])
                    total_count = operations_data.get('total_count', 0)
                    displayed_count = operations_data.get('displayed_count', 0)
                    last_updated = operations_data.get('last_updated', '')
                    
                    # 格式化最后更新时间
                    try:
                        update_time = datetime.fromisoformat(last_updated)
                        formatted_update_time = update_time.strftime('%Y-%m-%d %H:%M:%S')
                    except:
                        formatted_update_time = last_updated
                    
                    html = f'''
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MCP监控 - 操作详情</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" rel="stylesheet">
    <style>
        .status-healthy {{ color: #198754; }}
        .status-unhealthy {{ color: #dc3545; }}
        .operation-card {{ 
            border-left: 4px solid #dee2e6;
            transition: all 0.3s ease;
        }}
        .operation-card.success {{ border-left-color: #198754; }}
        .operation-card.danger {{ border-left-color: #dc3545; }}
        .operation-card:hover {{ 
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
            transform: translateY(-2px);
        }}
        .check-item {{
            padding: 0.25rem 0.5rem;
            margin: 0.25rem 0;
            border-radius: 0.25rem;
            font-size: 0.875rem;
        }}
        .check-healthy {{ background-color: #d1e7dd; color: #0f5132; }}
        .check-unhealthy {{ background-color: #f8d7da; color: #721c24; }}
        .navbar-brand {{ font-weight: bold; }}
        .stats-card {{ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }}
    </style>
</head>
<body class="bg-light">
    <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
        <div class="container">
            <a class="navbar-brand" href="/">
                <i class="bi bi-activity me-2"></i>MCP监控系统
            </a>
            <div class="navbar-nav ms-auto">
                <a class="nav-link" href="/">仪表板</a>
                <a class="nav-link active" href="/operations">监控操作</a>
                <a class="nav-link" href="/calculator-operations">运算操作</a>
            </div>
        </div>
    </nav>

    <div class="container mt-4">
        <div class="row">
            <div class="col-12">
                <div class="card stats-card text-white mb-4">
                    <div class="card-body">
                        <div class="row">
                            <div class="col-md-3">
                                <h5><i class="bi bi-list-check"></i> 总操作数</h5>
                                <h3>{total_count}</h3>
                            </div>
                            <div class="col-md-3">
                                <h5><i class="bi bi-eye"></i> 显示数量</h5>
                                <h3>{displayed_count}</h3>
                            </div>
                            <div class="col-md-6">
                                <h5><i class="bi bi-clock"></i> 最后更新</h5>
                                <h3>{formatted_update_time}</h3>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="row">
            <div class="col-12">
                <div class="card">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <h5 class="mb-0">
                            <i class="bi bi-list-ul me-2"></i>操作记录详情
                        </h5>
                        <button class="btn btn-outline-primary btn-sm" onclick="location.reload()">
                            <i class="bi bi-arrow-clockwise"></i> 刷新
                        </button>
                    </div>
                    <div class="card-body p-0">
'''
                    
                    if not operations:
                        html += '''
                        <div class="text-center p-5">
                            <i class="bi bi-inbox display-1 text-muted"></i>
                            <h4 class="text-muted mt-3">暂无操作记录</h4>
                            <p class="text-muted">系统还没有执行任何监控操作</p>
                        </div>
'''
                    else:
                        for i, operation in enumerate(operations):
                            status_class = operation.get('status_class', 'secondary')
                            status_text = operation.get('status_text', '未知')
                            formatted_time = operation.get('formatted_time', '')
                            check_details = operation.get('check_details', [])
                            success_rate = operation.get('success_rate', 0)
                            
                            # 状态图标
                            status_icon = 'bi-check-circle-fill' if operation.get('status') == 'healthy' else 'bi-x-circle-fill'
                            
                            html += f'''
                        <div class="operation-card {status_class} card m-3">
                            <div class="card-body">
                                <div class="row align-items-center">
                                    <div class="col-md-2">
                                        <div class="text-center">
                                            <i class="bi {status_icon} fs-1 status-{operation.get('status', 'unknown')}"></i>
                                            <div class="mt-2">
                                                <span class="badge bg-{status_class}">{status_text}</span>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4">
                                        <h6 class="mb-1">操作时间</h6>
                                        <p class="mb-0 text-muted">{formatted_time}</p>
                                        <small class="text-muted">成功率: {success_rate}%</small>
                                    </div>
                                    <div class="col-md-6">
                                        <h6 class="mb-2">检查项目详情</h6>
                                        <div class="row">
'''
                            
                            if check_details:
                                for check in check_details:
                                    check_status_class = 'check-healthy' if check.get('status') == 'healthy' else 'check-unhealthy'
                                    check_icon = 'bi-check' if check.get('status') == 'healthy' else 'bi-x'
                                    html += f'''
                                            <div class="col-md-6 mb-1">
                                                <div class="check-item {check_status_class}">
                                                    <i class="bi {check_icon} me-1"></i>
                                                    {check.get('name', '未知检查')}: {check.get('status_text', '未知')}
                                                </div>
                                            </div>
'''
                            else:
                                html += '''
                                            <div class="col-12">
                                                <p class="text-muted mb-0">无详细检查信息</p>
                                            </div>
'''
                            
                            html += '''
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
'''
                    
                    html += '''
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        // 自动刷新页面
        setInterval(function() {
            location.reload();
        }, 30000); // 30秒刷新一次
    </script>
</body>
</html>
'''
                    return html
                
                def generate_calculator_operations_html(self, calculator_data):
                    """生成计算器运算操作页面HTML"""
                    operations = calculator_data.get('operations', [])
                    total_count = calculator_data.get('total_count', 0)
                    displayed_count = calculator_data.get('displayed_count', 0)
                    last_updated = calculator_data.get('last_updated', '')
                    
                    # 格式化最后更新时间
                    try:
                        update_time = datetime.fromisoformat(last_updated)
                        formatted_update_time = update_time.strftime('%Y-%m-%d %H:%M:%S')
                    except:
                        formatted_update_time = last_updated
                    
                    # 统计不同类型的操作
                    operation_types = {}
                    for operation in operations:
                        op_type = operation.get('operation', '未知')
                        operation_types[op_type] = operation_types.get(op_type, 0) + 1
                    
                    html = f'''
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MCP监控 - 运算操作记录</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" rel="stylesheet">
    <style>
        .operation-card {{ 
            border-left: 4px solid #dee2e6;
            transition: all 0.3s ease;
        }}
        .operation-card.success {{ border-left-color: #198754; }}
        .operation-card.danger {{ border-left-color: #dc3545; }}
        .operation-card:hover {{ 
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
            transform: translateY(-2px);
        }}
        .navbar-brand {{ font-weight: bold; }}
        .stats-card {{ background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%); }}
        .type-badge {{
            font-size: 0.8rem;
            padding: 0.25rem 0.5rem;
        }}
        .result-box {{
            background-color: #f8f9fa;
            border: 1px solid #dee2e6;
            border-radius: 0.375rem;
            padding: 0.75rem;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            max-height: 100px;
            overflow-y: auto;
        }}
    </style>
</head>
<body class="bg-light">
    <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
        <div class="container">
            <a class="navbar-brand" href="/">
                <i class="bi bi-calculator me-2"></i>MCP监控系统
            </a>
            <div class="navbar-nav ms-auto">
                <a class="nav-link" href="/">仪表板</a>
                <a class="nav-link" href="/operations">监控操作</a>
                <a class="nav-link active" href="/calculator-operations">运算操作</a>
            </div>
        </div>
    </nav>

    <div class="container mt-4">
        <div class="row">
            <div class="col-12">
                <div class="card stats-card text-dark mb-4">
                    <div class="card-body">
                        <div class="row">
                            <div class="col-md-3">
                                <h5><i class="bi bi-calculator"></i> 总运算次数</h5>
                                <h3>{total_count}</h3>
                            </div>
                            <div class="col-md-3">
                                <h5><i class="bi bi-eye"></i> 显示数量</h5>
                                <h3>{displayed_count}</h3>
                            </div>
                            <div class="col-md-3">
                                <h5><i class="bi bi-tags"></i> 操作类型</h5>
                                <h3>{len(operation_types)}</h3>
                            </div>
                            <div class="col-md-3">
                                <h5><i class="bi bi-clock"></i> 最后更新</h5>
                                <h3>{formatted_update_time.split(' ')[1] if ' ' in formatted_update_time else formatted_update_time}</h3>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
'''
                    
                    # 添加操作类型统计
                    if operation_types:
                        html += '''
        <div class="row mb-4">
            <div class="col-12">
                <div class="card">
                    <div class="card-header">
                        <h5 class="mb-0"><i class="bi bi-pie-chart me-2"></i>操作类型统计</h5>
                    </div>
                    <div class="card-body">
                        <div class="row">
'''
                        for op_type, count in sorted(operation_types.items(), key=lambda x: x[1], reverse=True):
                            # 为不同操作类型设置不同颜色
                            type_colors = {
                                '加法运算': 'success', '减法运算': 'info', '乘法运算': 'warning', 
                                '除法运算': 'danger', '幂运算': 'primary', '平方根运算': 'secondary',
                                '阶乘运算': 'dark', '对数运算': 'success', '三角函数运算': 'info',
                                '表达式计算': 'primary', '统计分析': 'warning', '单位转换': 'secondary'
                            }
                            color = type_colors.get(op_type, 'secondary')
                            
                            html += f'''
                            <div class="col-md-3 mb-2">
                                <div class="d-flex justify-content-between align-items-center p-2 border rounded">
                                    <span>{op_type}</span>
                                    <span class="badge bg-{color}">{count}</span>
                                </div>
                            </div>
'''
                        
                        html += '''
                        </div>
                    </div>
                </div>
            </div>
        </div>
'''
                    
                    html += '''
        <div class="row">
            <div class="col-12">
                <div class="card">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <h5 class="mb-0">
                            <i class="bi bi-list-ul me-2"></i>运算操作记录
                        </h5>
                        <button class="btn btn-outline-primary btn-sm" onclick="location.reload()">
                            <i class="bi bi-arrow-clockwise"></i> 刷新
                        </button>
                    </div>
                    <div class="card-body p-0">
'''
                    
                    if not operations:
                        html += '''
                        <div class="text-center p-5">
                            <i class="bi bi-calculator display-1 text-muted"></i>
                            <h4 class="text-muted mt-3">暂无运算操作记录</h4>
                            <p class="text-muted">计算器还没有执行任何运算操作</p>
                        </div>
'''
                    else:
                        for i, operation in enumerate(operations):
                            status_class = operation.get('status_class', 'success')
                            status_text = operation.get('status_text', '成功')
                            formatted_time = operation.get('formatted_time', '')
                            operation_type = operation.get('operation', '未知操作')
                            result = operation.get('result', '无结果')
                            execution_time = operation.get('execution_time', 0)
                            
                            # 操作类型图标
                            type_icons = {
                                '加法运算': 'bi-plus-circle', '减法运算': 'bi-dash-circle',
                                '乘法运算': 'bi-x-circle', '除法运算': 'bi-slash-circle',
                                '幂运算': 'bi-arrow-up-circle', '平方根运算': 'bi-square-half',
                                '阶乘运算': 'bi-exclamation-circle', '对数运算': 'bi-graph-up',
                                '三角函数运算': 'bi-triangle', '表达式计算': 'bi-calculator',
                                '统计分析': 'bi-bar-chart', '单位转换': 'bi-arrow-left-right'
                            }
                            icon = type_icons.get(operation_type, 'bi-gear')
                            
                            # 状态图标
                            status_icon = 'bi-check-circle-fill' if operation.get('status') == 'success' else 'bi-x-circle-fill'
                            
                            html += f'''
                        <div class="operation-card {status_class} card m-3">
                            <div class="card-body">
                                <div class="row align-items-center">
                                    <div class="col-md-2">
                                        <div class="text-center">
                                            <i class="bi {icon} fs-1 text-primary"></i>
                                            <div class="mt-2">
                                                <span class="badge bg-{status_class}">{status_text}</span>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-3">
                                        <h6 class="mb-1">操作信息</h6>
                                        <p class="mb-1"><strong>{operation_type}</strong></p>
                                        <small class="text-muted">{formatted_time}</small>
                                        {f'<br><small class="text-info">执行时间: {execution_time:.4f}秒</small>' if execution_time > 0 else ''}
                                    </div>
                                    <div class="col-md-7">
                                        <h6 class="mb-2">运算结果</h6>
                                        <div class="result-box">
                                            {result[:500]}{'...' if len(result) > 500 else ''}
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
'''
                    
                    html += f'''
                    </div>
                </div>
            </div>
        </div>
        
        <div class="row mt-3">
            <div class="col-12 text-center">
                <small class="text-muted">最后更新: {formatted_update_time}</small>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        // 自动刷新页面
        setInterval(function() {{
            location.reload();
        }}, 30000); // 30秒刷新一次
    </script>
</body>
</html>
'''
                    return html
            
            # 创建处理器工厂
            def handler_factory(*args, **kwargs):
                return DashboardHandler(self, *args, **kwargs)
            
            port = self.config["dashboard"]["port"]
            server = HTTPServer(('localhost', port), handler_factory)
            
            self.logger.info(f"监控仪表板启动: http://localhost:{port}")
            server.serve_forever()
            
        except Exception as e:
            self.logger.error(f"仪表板启动失败: {e}")

def main():
    """主函数"""
    import argparse
    
    parser = argparse.ArgumentParser(description='MCP自动监控工具')
    parser.add_argument('--config', default='monitor_config.json', help='配置文件路径')
    parser.add_argument('--check-once', action='store_true', help='只执行一次检查')
    parser.add_argument('--dashboard-only', action='store_true', help='只启动仪表板')
    
    args = parser.parse_args()
    
    monitor = MCPAutoMonitor(args.config)
    
    if args.check_once:
        # 单次检查模式
        report = monitor.check_mcp_status()
        if report:
            print(json.dumps(report, indent=2, ensure_ascii=False))
    elif args.dashboard_only:
        # 仪表板模式
        monitor.start_dashboard()
    else:
        # 完整监控模式
        monitor.start_monitoring()

if __name__ == "__main__":
    main()